package com.naza.rpc.Server;


import com.naza.rpc.core.RpcSystemConfig;
import com.naza.rpc.filter.Filter;
import com.naza.rpc.filter.ServiceFilterBinder;
import com.naza.rpc.jmx.HashModuleMetricsVisitor;
import com.naza.rpc.jmx.ModuleMetricsHandler;
import com.naza.rpc.netty.RpcReceiveExecutor;
import com.naza.rpc.serialize.RpcSerializeProtocol;
import com.naza.rpc.util.ClassUtil;
import com.naza.rpc.annotation.Remote;

import java.util.Set;

/**
 *  rpc server manually bootstrap
 * @author yl
 */
public class BootStrap {

    private boolean autoDiscovery = false;

    private RpcReceiveExecutor messageRecvExecutor = RpcReceiveExecutor.getInstance();

    public BootStrap(String ip,String port,String echoApiPort){
        messageRecvExecutor.setServerAddress(ip+":"+port);
        messageRecvExecutor.setEchoApiPort(Integer.parseInt(echoApiPort));
    }

    public BootStrap setProtocol(String protocol){
        messageRecvExecutor.setSerializeProtocol(Enum.valueOf(RpcSerializeProtocol.class, protocol));
        return this;
    }

    public BootStrap addModule(String interfaceName, Class<?>... clazz){
        Object[] services = new Object[clazz.length];
        for(int i=0;i<clazz.length;i++){
            try {
                Class<?> c = clazz[i];
                ServiceFilterBinder binder = new ServiceFilterBinder();
                binder.setObject(c.newInstance());
                messageRecvExecutor.getHandlerMap().put(interfaceName,binder);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return this;
    }

    public BootStrap addModule(String interfaceName, Object impl, Filter filter){
        ServiceFilterBinder binder = new ServiceFilterBinder();
        binder.setFilter(filter);
        binder.setObject(impl);
        messageRecvExecutor.getHandlerMap().put(interfaceName,binder);
        return this;
    }

    public BootStrap autoDiscovery(boolean auto){
        this.autoDiscovery = auto;
        return this;
    }

    private void loadServiceByAnnotation(){
        Set<Class<?>> classes = ClassUtil.scan(Remote.class);
        for(Class clazz : classes){
            addModule(clazz.getGenericInterfaces()[0].getTypeName(),clazz);
        }
    }

    public void start(){
        if(autoDiscovery){
            loadServiceByAnnotation();
        }
        messageRecvExecutor.start();
        if (RpcSystemConfig.SYSTEM_PROPERTY_JMX_METRICS_SUPPORT) {
            HashModuleMetricsVisitor visitor = HashModuleMetricsVisitor.getInstance();
            visitor.signal();
            ModuleMetricsHandler handler = ModuleMetricsHandler.getInstance();
            handler.start();
        }
    }

    public void stop(){
        messageRecvExecutor.stop();
        if (RpcSystemConfig.SYSTEM_PROPERTY_JMX_METRICS_SUPPORT) {
            ModuleMetricsHandler handler = ModuleMetricsHandler.getInstance();
            handler.stop();
        }
    }
}
